<!DOCTYPE html>

<html>

<head>
    <title>发布-订阅模式</title>
    <link rel="stylesheet" type="text/css" href="../index.css"/>
    <style type="text/css">
    </style>
</head>
<body>
<div class="container">
    <h3>发布-订阅模式也称为观察者模式</h3>
</div>
<script type="text/javascript">
    (function() {
        // 发布-订阅模式又叫观察者模式，它定义了对象间得一种 一对多得依赖关系，当一个对象得状态发生改变时，所有依赖与它得对象将得到通知。
        /*// 当用户在点击document.body时需要进行一些相关得操作，由于不知道什么时候点击，只能通过addEventListener来定于click事件的触发，这也是一个发布-订阅模式
        document.body.addEventListener('click', function() {
            console.log(1)
        }, false)
        document.body.addEventListener('click', function() {
            console.log(2)
        }, false)
        document.body.addEventListener('click', function() {
            console.log(3)
        }, false)*/

        // 发布-订阅模式的实现
        // 1.首先确定发布者（好比售楼处）
        // 2.然后给发布者添加一个缓存列表，用于存放回调函数以便通知订阅者（售楼处的花名册）
        // 3.最后发布者（售楼处）会遍历这个缓存列表，依次出发里边列表中的订阅者回调函数

        /*var salesOffices = {};
        salesOffices.clientList = [];
        salesOffices.listen = function(fn) {
            this.clientList.push(fn)
        }
        salesOffices.trigger = function() {
            for (var i = 0; i < this.clientList.length; i++) {
                var fn = this.clientList[i];
                fn.apply(this, arguments)
            }
        }
        salesOffices.listen(function(price, squareMeter) {
            console.log(1)
            console.log(price, squareMeter)
        })
        salesOffices.listen(function(price, squareMeter) {
            console.log(2)
            console.log(price, squareMeter)
        })
        salesOffices.listen(function(price, squareMeter) {
            console.log(3)
            console.log(price, squareMeter)
        })

        // 售楼处进行发布
        salesOffices.trigger(18000, '100');
        salesOffices.trigger(20000, '88');
        // 上述发布-订阅模式存在一个稳定，只要你在售楼处已经订阅，发布者可能就回给你发布信息，这些信息可能不是你需要的
        // 对上述进行修改*/

        /*var salesOffices = {};
        salesOffices.clientList = {};
        salesOffices.listen = function(type, fn) {
            if (!this.clientList[type]) {
                this.clientList[type] = [];
            }
            this.clientList[type].push(fn);
        }
        salesOffices.trigger = function() {
            var key = Array.prototype.shift.call(arguments),
                list = this.clientList[key];
            if (!list || !list.length) {
                return false;
            }

            for (var i = 0, fn; fn = list[i++]; ) {
                fn.apply(this, arguments)
            }
        }

        salesOffices.listen('squareMeter88', function(price) {
            console.log('88-1');
            console.log('88平，价格：' + price)
        })

        salesOffices.listen('squareMeter88', function(price) {
            console.log('88-2');
            console.log('88平，价格：' + price)
        })

        salesOffices.listen('squareMeter100', function(price) {
            console.log('100平，价格：' + price)
        })
        salesOffices.trigger('squareMeter88', 18000)
        salesOffices.trigger('squareMeter100', 17000)

        // 以上优化后的代码中，发布者根据订阅者的需求进行选择性的发布*/



        /*// 通用的发布-订阅模式

        var observer = {

            clientList: [],

            listen: function(key, fn) {

                if (!this.clientList[key]) {

                    this.clientList[key] = []

                }

                this.clientList[key].push(fn);

            },

            trigger: function() {

                var key = Array.prototype.shift.call(arguments),

                    fns = this.clientList[key];



                if (!fns || fns.length === 0) {

                    return false;

                }



                for (var i = 0, fn; fn = fns[i++];) {

                    fn.apply(this, arguments)

                }

            },



            remove: function(key, FN) {

                var fns = this.clientList[key];

                if (!key && !FN) {

                    this.clientList = [];

                    return false

                }



                if (!key || !fns) {

                    return false;

                }



                if (!FN) {

                    fns && (fns.length = 0);

                    return false;

                }

                // 这里使用倒序循环

                for (var i = fns.length - 1; i >= 0; i--) {

                    var _fn = fns[i]

                    if (FN === _fn) {

                        fns.splice(i, 1);

                    }

                }

            }

        }



        var installEvent = function(obj) {

            for (var i in observer) {

                obj[i] = observer[i];

            }

        }



        var sellHouse = {};

        installEvent(sellHouse);





        sellHouse.listen('squareMeter88', sh_subscript_1 = function(price) {

            console.log('订阅者收1到88平价格：' + price)

        })

        sellHouse.listen('squareMeter88', sh_subscript_2 = function(price) {

            console.log('订阅者收2到88平价格：' + price)

        });

        sellHouse.listen('squareMeter100', sh_subscript_3 = function(price) {

            console.log('订阅者收1到100平价格：' + price)

        });

        sellHouse.remove('squareMeter88', sh_subscript_2);

        sellHouse.trigger('squareMeter88', 18000);

        sellHouse.trigger('squareMeter100', 17500);*/



        // 在大多数网站中都需要在登陆后进行操作，

        // 例如在登陆后进行通过权限加载列表，加载购物车列表，加载个人信息....

        // 虽然在异步请求中可以使用回调函数的方法进行，但是我们不知道除上述的操作之外是否含有另外的操作在登录后进行

        // 如果所有的回调都在login.succ中进行回调，会使其他代码与用户信息产生强耦合，会反复的修改登录函数

        // 如：

        // login.succ(function{

        // 		header.setAvatar();

        // 		nav.setAvatar();

        // 		card.load();

        // 		......

        // })



    })()

</script>

</body>

</html>